package com.powerteam.service.sys.impl;

import com.alibaba.fastjson.JSON;
import com.powerteam.exception.BusinessException;
import com.powerteam.mapper.sys.MenuMapper;
import com.powerteam.model.sys.Menu;
import com.powerteam.service.sys.MenuService;
import com.powerteam.vo.Result;
import com.powerteam.vo.TreeNode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 菜单相关服务接口实现
 *
 * @author jinming.zhang
 * @version 0.0.1
 * @date 2021/12/30
 */
@Slf4j
@Service
public class MenuServiceImpl implements MenuService {

    private static final String CLASS_NAME = "MenuServiceImpl";

    @Autowired
    private MenuMapper menuMapper;

    @Override
    public List<Menu> findAllMenu() {

        try {

            // 查询所有菜单信息
            List<Menu> allMenu = menuMapper.findAllMenu();
            log.info("{} findAllMenu 查询所有菜单 结果0:{}", CLASS_NAME, JSON.toJSON(allMenu));

            return allMenu;
        } catch (Exception e) {
            log.warn("{} findAllMenu 查询所有菜单异常", CLASS_NAME);
            log.error(e.getMessage(), e);
            return new ArrayList<>();
        }

    }

    @Override
    public List<TreeNode<Menu>> findUserMenuTree(Integer userId) {

        try {
            // 查询该用户的菜单信息
            List<Menu> userMenuTree = menuMapper.findUserMenuTree(userId);
            log.info("{} findUserMenuTree 查询用户菜单信息 入参0:{}, 结果0:{}", CLASS_NAME, userId, JSON.toJSON(userMenuTree));

            // 找到用户根菜单
            Menu userMenu = userMenuTree.stream().filter(menu -> menu.getPid() == null).findAny().get();

            List<TreeNode<Menu>> menuTree = this.findMenuTree(userMenu.getMenuId(), userMenuTree);
            log.info("{} findUserMenuTree 处理用户菜单信息 结果0:{}", CLASS_NAME, JSON.toJSON(menuTree));

            return menuTree;
        } catch (Exception e) {
            log.warn("{} findUserMenuTree 查询用户菜单信息异常 入参0:{}", CLASS_NAME, userId);
            log.error(e.getMessage(), e);
            return new ArrayList<>();
        }

    }

    @Override
    public List<TreeNode<Menu>> findAllMenuTree() {

        try {

            // 查询所有菜单(树形)
            List<Menu> menus = this.findAllMenu();
            Menu root = menus.stream().filter(menu -> menu.getPid() == null).findAny().get();
            List<TreeNode<Menu>> menuTree = this.findMenuTree(root.getMenuId(), menus);
            log.info("{} findAllMenuTree 查询所有菜单(树形) 结果0:{}", CLASS_NAME, JSON.toJSON(menuTree));

            return menuTree;
        } catch (Exception e) {
            log.info("{} findAllMenuTree 查询所有菜单(树形)异常", CLASS_NAME);
            log.error(e.getMessage(), e);
            return new ArrayList<>();
        }

    }

    @Override
    public List<Menu> findRoleMenu(Integer roleId) {

        try {
            // 查询某角色的菜单列表(列表)
            List<Menu> roleMenu = menuMapper.findRoleMenu(roleId);
            log.info("{} findRoleMenu 查询某角色的菜单列表(列表) 结果0:{}", CLASS_NAME, JSON.toJSON(roleMenu));

            return roleMenu;
        } catch (Exception e) {
            log.info("{} findRoleMenu 查询某角色的菜单列表(列表)异常", CLASS_NAME);
            log.error(e.getMessage(), e);
            return new ArrayList<>();
        }
    }

    /**
     * 检查是否存在该菜单
     *
     * @param menu
     * @return
     */
    @Override
    public Result checkMenu(Menu menu) {

        try {
            Boolean existMenu = menuMapper.existMenu(menu);
            log.info("{} checkMenu 检查是否存在该菜单 入参0:{} 结果0:{}", CLASS_NAME, JSON.toJSON(menu), existMenu);

            return new Result(!existMenu);
        } catch (Exception e) {
            log.info("{} checkMenu 检查是否存在该菜单异常 入参0:{}", CLASS_NAME, JSON.toJSON(menu));
            log.error(e.getMessage(), e);
            return new Result(false);
        }
    }

    @Override
    @Transactional(rollbackFor = {BusinessException.class}, propagation = Propagation.REQUIRED)
    public Result insert(Menu menu) {

        try {

            menu.setMenuIndex(menuMapper.findMaxMenuIndex() + 1);
            // 添加菜单
            boolean result = menuMapper.insert(menu) > 0;
            log.info("{} insert 添加菜单 入参0:{} 结果0:{}", CLASS_NAME, JSON.toJSON(menu), result);

            return new Result(result);
        } catch (Exception e) {
            log.warn("{} insert 添加菜单异常 入参0:{}", CLASS_NAME, JSON.toJSON(menu));
            log.error(e.getMessage(), e);
            throw new BusinessException("添加菜单失败");
        }
    }

    @Override
    @Transactional(rollbackFor = {BusinessException.class}, propagation = Propagation.REQUIRED)
    public Result delete(Integer menuId) {

        try {

            // 删除菜单
            boolean result = menuMapper.delete(menuId) > 0;
            log.info("{} delete 删除菜单 入参0:{} 结果0:{}", CLASS_NAME, menuId, result);

            return new Result(result);
        } catch (Exception e) {
            log.warn("{} delete 删除菜单异常 入参0:{}", CLASS_NAME, menuId);
            log.error(e.getMessage(), e);
            throw new BusinessException("删除菜单失败");
        }
    }

    @Override
    public Menu findById(Integer menuId) {

        try {
            Menu menu = menuMapper.findById(menuId);
            log.info("{} findById 根据菜单Id获取菜单信息 入参0:{} 结果0:{}", CLASS_NAME, menuId, JSON.toJSON(menu));

            return menu;
        } catch (Exception e) {
            log.warn("{} findById 根据菜单Id获取菜单信息异常 入参0:{}", CLASS_NAME, menuId);
            log.error(e.getMessage(), e);
            return new Menu();
        }
    }

    @Override
    @Transactional(rollbackFor = {BusinessException.class}, propagation = Propagation.REQUIRED)
    public Result update(Menu menu) {

        try {
            // 修改菜单信息
            boolean result = menuMapper.update(menu) > 0;
            log.info("{} update 修改菜单信息 入参0:{} 结果0:{}", CLASS_NAME, JSON.toJSON(menu), result);

            return new Result(result);
        } catch (Exception e) {
            log.warn("{} update 修改菜单信息异常 入参0:{}", CLASS_NAME, JSON.toJSON(menu));
            log.error(e.getMessage(), e);
            throw new BusinessException("修改菜单信息失败");
        }
    }

    /**
     * 上调菜单
     *
     * @param menuId
     * @return
     */
    @Override
    @Transactional(rollbackFor = {BusinessException.class}, propagation = Propagation.REQUIRED)
    public Result up(Integer menuId) {

        try {
            // 上一个菜单
            Menu previousMenu = menuMapper.findPreviousMenu(menuId);
            log.info("{} up 上调菜单 入参0:{} 结果0:{}", CLASS_NAME, menuId, JSON.toJSON(previousMenu));

            // 修改菜单
            return updateMenu(menuId, previousMenu);
        } catch (Exception e) {
            log.info("{} up 上调菜单异常 入参0:{}", CLASS_NAME, menuId);
            log.error(e.getMessage(), e);
            throw new BusinessException("上调菜单失败");
        }
    }

    /**
     * 下调菜单
     *
     * @param menuId
     * @return
     */
    @Override
    @Transactional(rollbackFor = {BusinessException.class}, propagation = Propagation.REQUIRED)
    public Result down(Integer menuId) {

        try {

            // 下一个菜单
            Menu nextMenu = menuMapper.findNextMenu(menuId);
            log.info("{} down 下调菜单 入参0:{} 结果0:{}", CLASS_NAME, menuId, JSON.toJSON(nextMenu));

            // 修改菜单
            return updateMenu(menuId, nextMenu);
        } catch (Exception e) {
            log.info("{} down 下调菜单异常 入参0:{}", CLASS_NAME, menuId);
            log.error(e.getMessage(), e);
            throw new BusinessException("下调菜单单失败");
        }
    }

    /**
     * 交换菜单位置
     *
     * @param menuId       当前菜单Id
     * @param exchangeMenu 交换的菜单
     * @return
     */
    @Transactional(rollbackFor = {BusinessException.class}, propagation = Propagation.REQUIRED)
    public Result updateMenu(Integer menuId, Menu exchangeMenu) {

        try {
            if (exchangeMenu != null) {
                // 查询当前菜单
                Menu thisMenu = this.findById(menuId);

                int tempMenuIndex = thisMenu.getMenuIndex();
                thisMenu.setMenuIndex(exchangeMenu.getMenuIndex());
                exchangeMenu.setMenuIndex(tempMenuIndex);

                // 交换
                if (!this.update(thisMenu).isSuccess() || !this.update(exchangeMenu).isSuccess()) {
                    throw new BusinessException();
                }
            }
            return new Result(true);
        } catch (Exception e) {
            log.warn("{} updateMenu 交换菜单失败 入参0:{} 1:{}", CLASS_NAME, menuId, JSON.toJSON(exchangeMenu));
            log.error(e.getMessage(), e);
            throw new BusinessException("上/下调菜单失败");
        }
    }

    /**
     * 递归菜单树
     *
     * @param pid   父Id
     * @param menus 菜单列表
     * @return
     */
    private List<TreeNode<Menu>> findMenuTree(int pid, List<Menu> menus) {

        // 递归根菜单并返回成树结构  List:[] node:{}  TreeNode:{{},[]}
        return menus.stream().filter(menu -> menu.getPid() != null && menu.getPid() == pid)
                .sorted(Comparator.comparing(Menu::getMenuIndex)).map(child -> {
                    TreeNode<Menu> node = new TreeNode<>();
                    node.setNode(child);
                    node.setChildren(this.findMenuTree(child.getMenuId(), menus));
                    return node;
                }).collect(Collectors.toList());

    }

}
